package com.ybg.block.core.fabric;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ybg.block.core.dbapi.entity.FabricApp;
import com.ybg.block.core.dbapi.entity.FabricChaincode;
import com.ybg.block.core.dbapi.entity.FabricChannel;
import com.ybg.block.core.dbapi.entity.FabricOrg;
import com.ybg.block.core.dbapi.service.FabricAppService;
import com.ybg.block.core.dbapi.service.FabricChaincodeService;
import com.ybg.block.core.dbapi.service.FabricChannelService;
import com.ybg.block.core.dbapi.service.FabricOrgService;
import com.ybg.share.core.fabric.FabricChaincodeRemoteApi;
import com.ybg.block.core.fabric.datamapper.FabricChaincodeDataMapper;
import com.ybg.share.core.fabric.dto.FabricChaincodeEditDTO;
import com.ybg.share.core.fabric.dto.FabricChaincodeQueryDTO;
import com.ybg.share.core.fabric.vo.FabricChaincodeVO;
import com.ybg.block.core.fabricbak.utils.MD5Util;
import com.ybg.framework.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service(version = "${dubbo.provider.version}", timeout = 120000, cache = "false")
public class FabricChaincodeRemoteApiImpl implements FabricChaincodeRemoteApi {
    @Autowired
    private FabricChaincodeService fabricChaincodeService;
    @Autowired
    private FabricAppService fabricAppService;
    @Autowired
    private FabricChannelService fabricChannelService;
    @Autowired
    private FabricOrgService fabricOrgService;

    @Override
    public R<?> editFabricChaincode(FabricChaincodeEditDTO dto) {
        FabricChaincode fabricChaincode = null;
        FabricChannel channel = null;

        if (dto.getId() == null && dto.getChannelId() == null) {
            return R.fail("请选择通道");
        }
        if (StrUtil.isBlank(dto.getName())) {
            return R.fail("链码名称不存在");
        }
        if (StrUtil.isBlank(dto.getPath())) {
            return R.fail("智能合约安装路径不存在");
        }
        if (StrUtil.isBlank(dto.getVersion())) {
            return R.fail("版本号不合法");
        }
        if (dto.getProposalWaitTime() == null || dto.getProposalWaitTime() < 1 || dto.getProposalWaitTime() > 60000 * 100) {
            return R.fail("超时时间不合法");
        }
        if (dto.getChaincodeEventListener() == null) {
            return R.fail("是否监听不能为空");
        }
        if (dto.getChaincodeEventListener() && StrUtil.isBlank(dto.getCallbackLocation())) {
            return R.fail("链码事件监听回调地址 不能为空");
        }
        if (dto.getChaincodeEventListener() && StrUtil.isBlank(dto.getEvents())) {
            return R.fail("链码监听事件名集合 不能为空");
        }
        if (dto.getId() != null) {
            fabricChaincode = fabricChaincodeService.getById(dto.getId());
            if (fabricChaincode == null) {
                return R.fail("数据不存在");
            }

            channel = fabricChannelService.getById(fabricChaincode.getChannelId());

        } else {
            fabricChaincode = new FabricChaincode();
            channel = fabricChannelService.getById(dto.getChannelId());
        }
        if (channel == null) {
            return R.fail("通道不存在");
        }

        fabricChaincode.setName(dto.getName());
        fabricChaincode.setSource(null);
        fabricChaincode.setPath(dto.getPath());
        fabricChaincode.setPolicy(null);
        fabricChaincode.setVersion(dto.getVersion());
        fabricChaincode.setProposalWaitTime(dto.getProposalWaitTime());
        fabricChaincode.setChannelId(dto.getChannelId());

        fabricChaincode.setChaincodeEventListener(dto.getChaincodeEventListener());
        fabricChaincode.setCallbackLocation(dto.getCallbackLocation());
        fabricChaincode.setEvents(dto.getEvents());
        fabricChaincode.setCreateTime(LocalDateTime.now());
        fabricChaincode.setLeagueId(channel.getLeagueId());
        fabricChaincode.setOrgId(channel.getOrgId());
        fabricChaincode.setPeerId(channel.getPeerId());
        fabricChaincode.setFlag(null);
        fabricChaincode.setChannelName(channel.getName());
        fabricChaincode.setPeerName(channel.getPeerName());
        fabricChaincode.setOrgName(channel.getOrgName());
        fabricChaincode.setLeagueName(channel.getLeagueName());
        fabricChaincode.setCc(createCC(fabricChaincode));
        fabricChaincodeService.saveOrUpdate(fabricChaincode);
        return null;
    }

    private String createCC(FabricChaincode chaincode) {
        FabricChannel channel = fabricChannelService.getById(chaincode.getChannelId());
        FabricOrg org = fabricOrgService.getById(channel.getOrgId());
        return MD5Util.md5(channel.getLeagueName() + org.getMspId() + channel.getPeerName() + channel.getName() + chaincode.getName());
    }

    @Override
    public R<?> deleteById(Long id) {
        FabricChaincode fabricChaincode = fabricChaincodeService.getById(id);
        if (fabricChaincode == null) {
            return R.fail("删除失败数据不存在");
        }
        fabricChaincodeService.removeById(id);
        Map<String, Object> condition = new LinkedHashMap<>(1);
        condition.put(FabricApp.CHAINCODE_ID, id);
        fabricAppService.removeByMap(condition);
        return R.success();
    }

    @Override
    public R<FabricChaincodeVO> getById(Long id) {
        FabricChaincode fabricChaincode = fabricChaincodeService.getById(id);
        return R.success(FabricChaincodeDataMapper.INSTANCE.toVO(fabricChaincode));
    }

    @Override
    public R<List<FabricChaincodeVO>> query(FabricChaincodeQueryDTO dto) {
        QueryWrapper<FabricChaincode> wrapper = new QueryWrapper<>();
        wrapper.eq(dto.getChannelId() != null, FabricChaincode.CHANNEL_ID, dto.getChannelId());
        wrapper.eq(dto.getId() != null, FabricChaincode.ID, dto.getId());
        wrapper.eq(dto.getLeagueId() != null, FabricChaincode.LEAGUE_ID, dto.getLeagueId());
        wrapper.eq(dto.getOrgId() != null, FabricChaincode.ORG_ID, dto.getOrgId());
        wrapper.eq(dto.getPeerId() != null, FabricChaincode.PEER_ID, dto.getPeerId());
        List<FabricChaincode> fabricChaincodeList = fabricChaincodeService.list(wrapper);
        return R.success(FabricChaincodeDataMapper.INSTANCE.toVOList(fabricChaincodeList));
    }
}
